<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .active{color:red}
    </style>
</head>
<body>
  

    
    <p>文字</p>
    <p>文字2</p>
    <div>good</div>
    
<script>


// var和let const的区别
// var是ES5语法，letconst是ES6语法;var有变量提升
// var和let是变量，可修改;const是常量，不可修改;
// let const有块级作用域, var没有


// typeof能判断哪些类型
// undefined string number boolean symbol
// object (注意, typeof null ===
// ‘'object' )
// function

// 列举强制类型转换和隐式类型转换
// 强制: parseInt parseFloat toString等
// 隐式: if、逻辑运算、==、+拼接字符串

// 手写深度比较lodash.isEqual
//测试
const obj1 = {
    a: 100 ,
    b: {
        x: 100,
        y: 200
    }
}

const obj2 = {
    a: 100 ,
    b: {
        x: 100,
        y: 200
    }
}

function isObject(obj){
    return typeof obj ==='object' && obj !==null;
}

function isEqual(obj1,obj2){
    if(!isObject(obj1)||!isObject(obj2)){
        return obj1 === obj2;
    }
    if(obj2===obj2){return true}
    for(let key in obj1){
        const res = isEqual(obj1[key],obj2[key]);
        if(!res){
            return false;
        }
    }
}
 

 //纯函数: 1.不改变源数组(没有副作用) ; 2.返回一个数组
const arr = [10, 20, 30, 40]
// concat
const arr1 = arr. concat( [50, 60, 70] )
// map
const arr2 = arr. map(num => num * 10)
// filter
const arr3 = arr. filter(num => num > 25)
// slice
const arr4 = arr.slice( )
//非纯函数
// push
// pop shift unshift
// forEach 
// some every.
// reduce


// const arr = [10, 20, 30, 40, 50]
// // slice纯函数
// const arr1 = arr.slice( )
// const arr2 = arr.slice(1, 4)
// const arr3 = arr.slice(2 )
// const arr4 = arr.slice(-2)

// splice非纯函数
// const spliceRes = arr.splice(1, 2,'a', 'b', 'c' )
// console. Log(spliceRes, arr)

// [10,20,30].map(parseInt)
// parseInt()
// parseInt("ffffff",16)

// 函数call和apply的区别
// fn.call(this , p1, p2, p3)
// fn.apply(this,arguments )

// 事件代理(委托)是什么
// 利用事件冒泡个子元素，绑定事件


// 闭包是什么?有何特性?有何影响?
// 回顾作用域和自由变量
// 回顾闭包应用场景:作为参数被传入,作为返回值被返回
// ; 回顾:自由变量的查找,要在函数定义的地方(而非执行的地方)
//  闭包函数作为返回值 内存不会释放


// 解释jsonp原理,为何不是真正的ajax
// ◆浏览器的同源策略(服务端没有同源策略)和跨域
// ◆哪些html标签能绕过跨域?

// ==和===的区别
// ==会尝试类型转换
// ===严格相等
// 哪些场景才用== ?


// new Object()和Object.create()区别
// ◆{} 等同于new Object( , 原型Object.prototype
// ◆Object.create(nul) 没有原型
// ◆Object.crete(..) 可指定原型

var obj1 = Object.create(null);
var obj2 = Object.create({name:"mumu",age:18})


// 字符串字母开头,后面字母数字下划线,长度6-30
// ◆constreg = A^[a-zA-Z]\w{5,29}$/

let  a = 100;
function test(){
    alert(a);
    a = 10;
    alert(a);
}
test();
alert(a);
// 100 10 10
// 定义函数不管，什么时候执行，什么时候看里面代码



手写字符串trim保证浏览器兼容性
String.prototype.trim= function(){
return this. replace(/^\s+/,'' ).replace(/\s+$/,'')
}
// (原型、 this、正则表达式)


// 获取多个数字中的最大值


// 如何用JS实现继承
// class继承
// prototype继承


// 如何捕获JS中的异常?
// try {
// // todo
// } catch (ex) {
// console.error(ex) //手动捕获catch
// } finally {
// // todo
// }

// window. onerror = function (message, source, lineNom， colNom, error) {
// //第一，对跨域的js，如CDN的，不会有详细的报错信息
// //第二，对于压缩的js，还要配合sourceMap 反查到未压缩代码的行、列
// }



// 什么是JSON ?
// json是一种数据格式,本质是一段字符串。
// json格式和JS对象结构一致,对JS语言更友好
// window.JSON是一个全局对象: JSON.stringify JSON.parse

// 获取当前页面url参数

// function query(name) {
// const search = location.search.substr(1) //类似array.slice(
// // search: 'a=10&b=20&c=30
// const reg = new RegExp( (^ |&)${name}=( [^&]*)(&|$)，'i')
// const res = search. match( reg)
// if (res === null) {
// return null 
// }
// console. Log(res)
// return res [2]
// }
// query('b')


// URLSearchParams
// function query(name) {
// const search = location.search
// const p = new URL SearchParams ( search)
// return p.get(name)
// }


// 手写flatern考虑多层级
Array.prototype.concat.apply([],arr);

function flat(arr){
    const isDeep = arr.some(item=>item instanceof Array);
    if(!isDeep){
        return arr;
    }
    const res = Array.prototype.concat.apply([],arr);
    return flat(res);
}

// 去重

// //传统方式
function unique(arr) {
    const
    res = [] 
    arr. forEach(item => { 
        if ( res.indexOf(item) < 0) {    
            res.push( item)    
        }
    
    })    
    return res
}
const res = unique( [30, 10, 20, 30, 40, 10])
console. Log(res)

//使用Set (无序，)
function unique(arr) {
    const set = new Set(arr)
    return  [... set]
}

// 手写深拷贝
// object.assign

// 介绍RAF requetAnimateFrame
// 要想动画流畅,更新频率要60帧/s , 即16.67ms更新一次视图
// setTimeout要手动控制频率,而RAF浏览器会自动控制
// 后台标签或隐藏iframe中, RAF会暂停,而setTimeout依然执行

function animate(){
    num = num+3;
    mybox.style.width=num;
    if(num<300){
        window.requestAnimationFrame(animate);
    }
}


// 如何性能优化,从哪几个方面考虑
// 原则:多使用内存、缓存,减少计算、减少网路请求
// 方向:加载页面,页面渲染，页面操作流畅度

</script>
</body>
</html>

 
